package com.abel.bigwater.data.sanchuan

import com.abel.bigwater.data.BcdString
import com.abel.bigwater.data.mapper.DataMapper
import com.abel.bigwater.data.mapper.RtuMapper
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.socket.DatagramPacket
import org.slf4j.LoggerFactory
import java.util.*

class SanchuanUdpHandler(dataMapper: DataMapper, rtuMapper: RtuMapper, firmId: String, firmCode: String) : SanchuanTcpHandler(dataMapper, rtuMapper, firmId, firmCode) {
    override fun channelRead(ctx: ChannelHandlerContext?, msg: Any?) {
        lgr.info("GOT UDP: ${msg}")
        if (msg is DatagramPacket) {
            lgr.info("UDP:\n${BcdString.hexString(msg.content())}")

            try {
                val p = SanchuanPacket.parseBuffer(msg.content())

                handlePacket(p!!, ctx)

                replyDatagram(msg, p, ctx)
            } catch (ex: Exception) {
                lgr.error("处理UDP异常: ${ex.message}", ex)
            }
        }
    }

    fun replyDatagram(dp: DatagramPacket, msg: SanchuanPacket, ctx: ChannelHandlerContext?) {
        when (msg.ctrlb) {
            CtrlbType.Online -> {
                // send back online-reply.
                val reply = SanchuanPacket().apply {
                    this.ctrlb = CtrlbType.OnlineReply
                    this.actrlb = 0
                    this.meterId = msg.meterId
                    this.data = MeterOnlineReply(null).also {
                        it.serverTime = Date()
                        it.serverState = ServerStateType.SendCommand
                    }
                }

                ctx!!.alloc().buffer().also {
                    reply.fillBuffer(it)
                    lgr.info("Write back to meter:\n${BcdString.hexString(it, null, true)} to ${dp.sender()}")
                    ctx.writeAndFlush(DatagramPacket(it, dp.sender()))
                }
            }
        }
    }

    /**
     * should overwrite exception-caught, because UDP context CANNOT be closed.
     */
    override fun exceptionCaught(ctx: ChannelHandlerContext?, cause: Throwable?) {
        lgr.error("UDP端口异常: ${cause?.message}", cause)
    }

    companion object {
        private val lgr = LoggerFactory.getLogger(SanchuanUdpHandler::class.java)
    }
}